package com.juben.svr.demos.web;

import com.itextpdf.html2pdf.ConverterProperties;
import com.itextpdf.html2pdf.HtmlConverter;
import com.itextpdf.kernel.pdf.EncryptionConstants;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.html2pdf.HtmlConverter;
import com.itextpdf.kernel.pdf.WriterProperties;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.element.AreaBreak;
import com.itextpdf.layout.font.FontProvider;
import com.itextpdf.styledxmlparser.css.media.MediaDeviceDescription;
import com.itextpdf.styledxmlparser.css.media.MediaType;

import com.itextpdf.text.DocumentException;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfStamper;
import com.juben.svr.domain.ApiResponse;
import com.juben.svr.domain.ResponseMessage;
import com.juben.svr.domain.UWorks;
import com.juben.svr.service.TokenService;
import com.juben.svr.service.UworkService;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.SystemUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.convert.ConversionException;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;


import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;

@RestController
@RequestMapping("/api")
@CrossOrigin(origins = "http://localhost:5173",allowedHeaders = "*",allowCredentials = "true")
public class WritePdf {
    private static final String outputDir = "D:\\学习资料\\毕业设计\\pdfs";

    @Autowired
    private TokenService tokenService;

    @Autowired
    private UworkService uworkService;
    @PostMapping("/write-pdf")
    public String writePdf(@RequestBody PdfRequest request, UWorks uwork) throws IOException {
        // 确保HTML模板文件存在并获取其输入流
<<<<<<< HEAD
       //final InputStream is = Objects.requireNonNull(ItextChinese.class.getResourceAsStream("/Template.html"));
=======
        //final InputStream is = Objects.requireNonNull(IText7ChineseFont.class.getResourceAsStream("/Template.html"));
>>>>>>> 38a1dbe3941ebf5713fbf4c6d3dbf69154c425d3
        // 读取HTML内容，并指定字符集为UTF-8以确保正确解析中文字符
        //final String html = IOUtils.toString(is, StandardCharsets.UTF_8);
        // 直接使用从前端传来的HTML内容，无需读取模板文件
        String Html = request.getHtml(); // 确保HTML内容是干净的
<<<<<<< HEAD
        String wid = request.getWid();  // 确保wid是干净的
        System.out.println("write-pdf=========wid:" + wid);
        // 清理 HTML（去掉不必要的标签）
        String cleanHtml = Html.replaceAll("<br>", "").trim(); // 根据需求定制清理逻辑
=======
        String wid = request.getWid();
        System.out.println("write-pdf=========wid:" + wid);
>>>>>>> 38a1dbe3941ebf5713fbf4c6d3dbf69154c425d3
        uwork.setWname(uworkService.getworkByID(wid).getWname());
        String finalHtml = "<!DOCTYPE html>\n" +
                "<html lang=\"zh\">\n" +
                "<head>\n" +
                "    <meta charset=\"UTF-8\">\n" +
                "    <title>"+uwork.getWname()+"剧本"+"</title>\n" +
                "    <style>\n" +
<<<<<<< HEAD
=======
                "        @media print {\n" +
                "            @page {\n" +
                "                size: A4;\n" +
                "                margin: 0;\n" +
                "            }\n" +
                "        }\n" +
>>>>>>> 38a1dbe3941ebf5713fbf4c6d3dbf69154c425d3
                "        html,\n" +
                "        body,\n" +
                "        div,\n" +
                "        ul,\n" +
                "        li,\n" +
                "        h1,\n" +
                "        h2,\n" +
                "        h3,\n" +
                "        h4, h5, h6,\n" +
                "        p,\n" +
<<<<<<< HEAD
                "        ol\n" +
=======
                "        ol,\n" +
>>>>>>> 38a1dbe3941ebf5713fbf4c6d3dbf69154c425d3
                "        pre {\n" +
                "            margin: 0;\n" +
                "            padding: 0;\n" +
                "            font-weight: normal;\n" +
                "            text-align: justify\n" +
                "        }\n" +
                "        u{\n" +
<<<<<<< HEAD
                "            text-decoration: underline;\n" +
                "        }\n" +
                "        s{\n" +
                "            text-decoration: line-through;\n" +
=======
                "            text-decoration: underline; /*下划线*/\n" +
                "        }\n" +
                "        s{\n" +
                "            text-decoration: line-through;  /*删除线*/\n" +
>>>>>>> 38a1dbe3941ebf5713fbf4c6d3dbf69154c425d3
                "        }\n" +
                "\n" +
                "        pre, p {\n" +
                "            white-space: pre-wrap;\n" +
                "            word-wrap: break-word;\n" +
                "            text-align: justify;\n" +
                "        }\n" +
                "\n" +
                "        body {\n" +
<<<<<<< HEAD
                "            with: 200px;\n" +
                "            height: 800px;\n" +
                "             baground-color: yellow"+
=======
>>>>>>> 38a1dbe3941ebf5713fbf4c6d3dbf69154c425d3
                "            padding: 20px;\n" +
                "        }\n" +
                "        strong{\n" +
                "            font-weight: bold;\n" +
                "        }\n" +
                "        .ql-align-center {\n" +
                "            text-align: center;\n" +
                "        }\n" +
                "\n" +
                "        .ql-align-right {\n" +
                "            text-align: right;\n" +
                "        }\n" +
                "\n" +
                "        .ql-align-justify em{\n" +
<<<<<<< HEAD
                "            text-align: justify !important;\n" +
=======
                "            text-align: justify !important;    /*文本两端对齐*/\n" +
>>>>>>> 38a1dbe3941ebf5713fbf4c6d3dbf69154c425d3
                "        }\n" +
                "\n" +
                "        h1 {\n" +
                "            margin-bottom: 20px;\n" +
                "        }\n" +
                "\n" +
                "        h2 {\n" +
                "            margin-bottom: 10px;\n" +
                "        }\n" +
                "    </style>\n" +
                "</head>\n" +
<<<<<<< HEAD
                "<body>"  +cleanHtml + "</body>\n" +
=======
                "<body>" + Html + "</body>\n" +
>>>>>>> 38a1dbe3941ebf5713fbf4c6d3dbf69154c425d3
                "</html>";

        System.out.println("write-pdf=========finalHtml:" + finalHtml);
        String fileName = "";
        //final String html = IOUtils.toString(finalHtml, StandardCharsets.UTF_8);
        // 使用阿里巴巴字体将HTML转换为PDF并保存PDF文件
        //html2pdf("alibaba", finalHtml, getAlibabaFontDirectory());
        // 使用Source Han Sans字体将HTML转换为PDF并保存PDF文件
        //html2pdf("source sans", html, getSourceHanSansFontDirectory());
        // 使用Source Han Serif字体将HTML转换为PDF并保存PDF文件
        //html2pdf("source serif", html, getSourceHanSerifFontDirectory());
        try {
            fileName = html2pdf(wid, finalHtml, getAlibabaFontDirectory(),"userPassword","ownerPassword");
            try {
                uwork.setWID(wid);
                uwork.setPname(fileName);
                System.out.println("剧本信息：" + uwork);
                uworkService.updateUWorks(uwork);
            }catch (Exception e){
                e.printStackTrace();
                return "pdf文件名修改失败";
            }
        } catch (IOException e) {
            System.err.println("文件操作失败：" + e.getMessage());
        } catch (ConversionException e) {
            System.err.println("转换过程中出现问题：" + e.getMessage());
        } catch (Exception e) {
            System.err.println("未知错误：" + e.getMessage());
        }
        return fileName;
    }


    /**
     * 将HTML字符串转换为PDF文件，并支持中文字体。
     *
     * @param name PDF文件的名称前缀，用于标识生成的文件。
     * @param html 要转换的HTML内容字符串。
     * @param fontDir 字体目录的路径，用于加载中文字体。
     * @throws Exception 如果转换过程中发生错误，则抛出异常。
     */
    private static String html2pdf(String name, String html, String fontDir, String userPassword, String ownerPassword) throws Exception {
        // 指定PDF文件保存的文件夹路径
        final File outputFolder = new File(outputDir);
        // 确保输出文件夹存在
        if (!outputFolder.exists() && !outputFolder.mkdirs()) {
            throw new IOException("无法创建输出文件夹: " + outputDir);
        }
        // 创建一个指定路径下的文件，用于存储生成的PDF
        final File file = new File(outputFolder, name + ".pdf");
        //获取文件名
        String fileName = file.getName();
        System.out.println("pdf文件名：" + fileName);
        // 初始化转换属性
        final ConverterProperties properties = new ConverterProperties();
        // 初始化字体提供者，并加载指定目录下的字体
        final FontProvider fontProvider = new FontProvider();
        fontProvider.addDirectory(fontDir);
        properties.setFontProvider(fontProvider);


        // 清理 HTML（去掉不必要的标签）
        String cleanHtml = html.replaceAll("<br>", "").trim();


        // 设置媒体设备描述，这里假设是打印介质
        properties.setMediaDeviceDescription(new MediaDeviceDescription(MediaType.PRINT));
        // 使用try-with-resources确保资源被正确关闭
        try (final OutputStream os = Files.newOutputStream(file.toPath());
             final PdfWriter pdfWriter = new PdfWriter(os, new WriterProperties().setStandardEncryption(
                     userPassword.getBytes(),   // 用户密码
                     ownerPassword.getBytes(),  // 所有者密码
                     EncryptionConstants.ALLOW_PRINTING,    // 允许打印
                     256));    // 加密级别为128位
             final PdfDocument pdfDocument = new PdfDocument(pdfWriter)) {

            // 转换HTML字符串为PDF文档
            //HtmlConverter.convertToPdf(cleanHtml, pdfDocument, properties);

            // 转换HTML字符串为PDF文档
            try (
<<<<<<< HEAD
                    final Document doc = HtmlConverter.convertToDocument(cleanHtml, pdfDocument, properties);) {
=======
                    final Document doc = HtmlConverter.convertToDocument(html, pdfDocument, properties)) {
>>>>>>> 38a1dbe3941ebf5713fbf4c6d3dbf69154c425d3
                // 添加一个区域断页，确保内容在新的页面开始
                doc.add(new AreaBreak());
            }
        }
        // 输出文件的绝对路径，以便于调试和确认文件位置
        System.out.println(name + ": " + file.getAbsolutePath());
        return fileName;
    }

<<<<<<< HEAD
    // 定义一个方法用于清理HTML内容
    private static String cleanHtmlContent(String html) {
        // 在这里进行详细的 HTML 清理
        // 比如移除多余属性，标签和其他不需要的内容
        return html.replaceAll("<br>", "").trim(); // 根据需求调整
    }

=======
>>>>>>> 38a1dbe3941ebf5713fbf4c6d3dbf69154c425d3
    /**
     * 获取用于存储阿里巴巴字体文件的目录
     * 这个方法在系统临时目录下创建一个唯一目录，并从类路径资源中复制阿里巴巴字体文件到该目录
     * 如果目录创建失败或字体文件无法复制，则抛出异常
     *
     * @return 存储阿里巴巴字体文件的目录路径
     * @throws IOException 如果字体文件无法复制到目录中，则抛出此异常
     */
    private static String getAlibabaFontDirectory() throws IOException {
        // 创建一个唯一的目录路径，用于存放字体文件
        final File fontDir = new File(SystemUtils.getJavaIoTmpDir(), UUID.randomUUID().toString());
        // 如果目录不存在且无法创建，则抛出异常
        if (!fontDir.exists() && !fontDir.mkdirs()) {
            throw new IllegalStateException();
        }
        //从类路径资源中加载轻量级字体文件
        final InputStream fontLight = Objects.requireNonNull(WritePdf.class.getResourceAsStream("/fonts/AlibabaPuHuiTi-2-45-Light.ttf"));
        // 从类路径资源中加载粗体字体文件
        final InputStream fontBold = Objects.requireNonNull(WritePdf.class.getResourceAsStream("/fonts/AlibabaPuHuiTi-2-85-Bold.ttf"));
        // 将字体文件复制到创建的目录中
        IOUtils.copy(fontLight, Files.newOutputStream(new File(fontDir, "AlibabaPuHuiTi-2-45-Light.ttf").toPath()));
        IOUtils.copy(fontBold, Files.newOutputStream(new File(fontDir, "AlibabaPuHuiTi-2-85-Bold.ttf").toPath()));

        // 注册一个关闭钩子，在JVM关闭时删除创建的目录及其内容
        Runtime.getRuntime().addShutdownHook(new Thread(() -> FileUtils.deleteQuietly(fontDir)));
        // 返回存储字体文件的目录的绝对路径
        return fontDir.getAbsolutePath();
    }
    /**
     * 获取SourceHanSans字体目录
     *
     * @return 字体目录的绝对路径
     * @throws IOException 如果无法访问字体资源文件
     * 此方法负责创建一个临时目录，并在其中存放必要的字体文件
     * 它确保了字体文件被正确地从资源中提取并设置在该目录下
     */
//    private static String getSourceHanSansFontDirectory() throws IOException {
//        // 创建一个唯一的临时目录来存放字体文件
//        final File fontDir = new File(SystemUtils.getJavaIoTmpDir(), UUID.randomUUID().toString());
//        // 如果目录不存在且无法创建，则抛出异常
//        if (!fontDir.exists() && !fontDir.mkdirs()) {
//            throw new IllegalStateException();
//        }
//        // 从资源中获取字体文件输入流，字体重量分别为Light和Bold
//        final InputStream fontLight = Objects.requireNonNull(WritePdf.class.getResourceAsStream("/fonts/SourceHanSansSC-ExtraLight.otf"));
//        final InputStream fontBold = Objects.requireNonNull(WritePdf.class.getResourceAsStream("/fonts/SourceHanSansSC-Medium.otf"));
//        // 将字体文件复制到临时目录中
//        IOUtils.copy(fontLight, Files.newOutputStream(new File(fontDir, "SourceHanSansSC-ExtraLight.otf").toPath()));
//        IOUtils.copy(fontBold, Files.newOutputStream(new File(fontDir, "SourceHanSansSC-Medium.otf").toPath()));
//
//        // 注册一个关闭钩子，在JVM关闭时删除临时目录
//        Runtime.getRuntime().addShutdownHook(new Thread(() -> FileUtils.deleteQuietly(fontDir)));
//        // 返回临时目录的绝对路径
//        return fontDir.getAbsolutePath();
//    }
    /**
     * 获取SourceHanSerif字体目录
     *
     * 本方法尝试创建一个临时目录，并将必要的字体文件复制到该目录
     * 如果目录创建失败或者字体文件复制失败，将抛出异常
     * 在程序退出时，通过关闭钩子删除该临时目录
     *
     * @return 字体目录的绝对路径
     * @throws IOException 如果字体文件复制失败或目录创建失败
     */
<<<<<<< HEAD
    private static String getSourceHanSerifFontDirectory() throws IOException {
        // 创建一个位于系统临时目录下的唯一目录，用于存放字体文件
        final File fontDir = new File(SystemUtils.getJavaIoTmpDir(), UUID.randomUUID().toString());
        // 如果目录不存在且创建目录失败，则抛出异常
        if (!fontDir.exists() && !fontDir.mkdirs()) {
            throw new IllegalStateException();
        }
        // 从类路径资源中加载字体文件
        final InputStream fontLight = Objects.requireNonNull(WritePdf.class.getResourceAsStream("/fonts/145kRdIjxgfd.woff"));
        final InputStream fontBold = Objects.requireNonNull(WritePdf.class.getResourceAsStream("/fonts/asH5DYSMf9aP.woff"));
        // 将字体文件复制到临时目录中
        IOUtils.copy(fontLight, Files.newOutputStream(new File(fontDir, "145kRdIjxgfd.woff").toPath()));
        IOUtils.copy(fontBold, Files.newOutputStream(new File(fontDir, "asH5DYSMf9aP.woff").toPath()));

        // 注册关闭钩子，在程序退出时删除临时目录
        Runtime.getRuntime().addShutdownHook(new Thread(() -> FileUtils.deleteQuietly(fontDir)));
        // 返回字体目录的绝对路径
        return fontDir.getAbsolutePath();
    }
=======
//    private static String getSourceHanSerifFontDirectory() throws IOException {
//        // 创建一个位于系统临时目录下的唯一目录，用于存放字体文件
//        final File fontDir = new File(SystemUtils.getJavaIoTmpDir(), UUID.randomUUID().toString());
//        // 如果目录不存在且创建目录失败，则抛出异常
//        if (!fontDir.exists() && !fontDir.mkdirs()) {
//            throw new IllegalStateException();
//        }
//        // 从类路径资源中加载字体文件
//        final InputStream fontLight = Objects.requireNonNull(WritePdf.class.getResourceAsStream("/fonts/SourceHanSerifSC-ExtraLight.otf"));
//        final InputStream fontBold = Objects.requireNonNull(WritePdf.class.getResourceAsStream("/fonts/SourceHanSerifSC-Medium.otf"));
//        // 将字体文件复制到临时目录中
//        IOUtils.copy(fontLight, Files.newOutputStream(new File(fontDir, "SourceHanSerifSC-ExtraLight.otf").toPath()));
//        IOUtils.copy(fontBold, Files.newOutputStream(new File(fontDir, "SourceHanSerifSC-Medium.otf").toPath()));
//
//        // 注册关闭钩子，在程序退出时删除临时目录
//        Runtime.getRuntime().addShutdownHook(new Thread(() -> FileUtils.deleteQuietly(fontDir)));
//        // 返回字体目录的绝对路径
//        return fontDir.getAbsolutePath();
//    }
>>>>>>> 38a1dbe3941ebf5713fbf4c6d3dbf69154c425d3
    //查看pdf，剧本内容显示
    @PostMapping ("/view-pdf")
    public ResponseEntity<Resource> viewPdf(@RequestBody Map<String, String> request, @RequestHeader ("Authorization") String token) {
        System.out.println("viewPdf");
        // 从请求中提取 wid
        String wid = request.get("wid");
        System.out.println("获取到的wid: " + wid);
        System.out.println("获取到的token:"+token);
        //用户身份鉴权
        // 从 Authorization 头中提取 JWT 令牌
        System.out.println("token:"+token);
        if (token != null && token.startsWith("Bearer ")) {
            token = token.substring(7); // 删除 "Bearer " 前缀
        } else {
            System.err.println("无效的授权 token");
            throw new RuntimeException("无效的授权 token"); // 抛出异常
        }
        //鉴权用户
        try {
            // 验证令牌并解析用户 ID
            System.out.println("开始解析用户id");
            Integer userId = tokenService.getUserIdFromToken(token);
            System.out.println("userId:"+userId);
            if (userId != null){
                System.out.println("用户身份鉴权通过");
                String password = "ownerPassword"; // PDF文件的密码
                String encryptedPdfPath = "D:\\学习资料\\毕业设计\\pdfs\\" + wid + ".pdf"; // 加密PDF文件的路径
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                PdfReader reader = new PdfReader(encryptedPdfPath, password.getBytes());
                PdfStamper stamper = new PdfStamper(reader, baos);
                stamper.close();
                reader.close();
                System.out.println("PDF解密成功");
                byte[] pdfBytes = baos.toByteArray();
<<<<<<< HEAD

=======
>>>>>>> 38a1dbe3941ebf5713fbf4c6d3dbf69154c425d3
                ByteArrayResource resource = new ByteArrayResource(pdfBytes);
                System.out.println("PDF获取成功:"+resource);
                System.out.println("PDF获取成功，返回");
                return ResponseEntity.ok()
                        .contentType(org.springframework.http.MediaType.APPLICATION_PDF)
                        .header(HttpHeaders.CONTENT_DISPOSITION, "inline; filename=decrypted.pdf")
                        .body(resource);
            }else {
                System.out.println("用户身份鉴权失败,打开pdf失败");

                return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(null);
            }
        } catch (IOException e) {
            System.err.println("PDF解密失败");
            e.printStackTrace();
            return ResponseEntity.internalServerError().build();
        } catch (DocumentException e) {
            System.out.println("PDF解密失败");
            throw new RuntimeException(e);
        }
    }

}
class PdfRequest {
    private String html; // 用于存储富文本内容（HTML格式）
    private String wid;

    // Getters and Setters
    public String getHtml() {
        return html;
    }

    public void setHtml(String html) {
        this.html = html;
    }

    public String getWid() {
        return wid;
    }

    public void setWid(String wid) {
        this.wid = wid;
    }
}
